package cn.shangqizhenshuai.sqiot.mqtt;

import org.apache.log4j.Logger;
import org.eclipse.paho.client.mqttv3.*;
import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;

import java.util.concurrent.ScheduledExecutorService;
@Service("mqttservice")
public class Mqttservice {

    public Logger log = Logger.getLogger(Mqttservice.class);

    private String HOST = "";
    //private String TOPIC = "/hello";
    private String clientid = "sqiot";
    private MqttClient client;
    private MqttConnectOptions options;
    private String userName = "sq";
    private String passWord = "11111";

    private ScheduledExecutorService scheduler;

    private boolean automaticReconnection = false; //是否自动重连 默认诶false

    private boolean cleanSession = true;//是否保持session，true无法接受离线消息， false可以接受离线消息


    private int connectionTimeout = 30;//连接超时时间

    private int keepAliveInterval = 60;//心跳时间

    private String version = "3.1.1";//可选版本3.0 3.1.1


    //下面是遗嘱消息的设置

    private String willTopic="/state";//将遗嘱消息发布到那个主题

    private String willPayload="death";//遗嘱消息内容

    private int willQos = 2;//遗嘱消息级别

    private boolean willretained = false;//是否保留这个遗嘱消息

    //启动成功消息的设置
    private String startTopic=null;//将启动消息发布到那个主题

    private String startPayload="OK";//遗嘱消息内容

    private int startlQos = 2;//遗嘱消息级别

    private boolean startretained = false;//是否保留这个遗嘱消息


    /**
     * 关闭消息
     * @return
     */
    public boolean shutdown() {
        try {
            client.disconnect();

        } catch (MqttException e) {
            e.printStackTrace();
            return false;
        }
        return true;
    }


//设置断开连接的消息消息
    public void setWill(String topic,String payload,int qos,boolean retainedd){
        log.debug("正在设置断开成功消息。。。");
        this.willTopic = topic;
        this.willPayload = payload;
        this.willQos = qos;
        this.willretained = retainedd;
    }

//设置启动成功的消息
    public void setState(String startTopic,String startPayload,int startlQos){
    log.debug("正在设置启动成功消息。。。");
    this.startTopic = startTopic;
    this.startPayload = startPayload;
    this.startlQos = startlQos;
    this.startretained = startretained;
    }

    /**
     *查询当前服务状态
     * @return
     */
    public boolean clientstate(){
        return client.isConnected();
    }

    /**
     * 启动mqtt
     * @param mqttCallback 回调函数
     * @return 客户端
     */
    public MqttClient start(MqttCallback mqttCallback) {
        try {
            log.debug("设置连接启动信息。。。");
            // host为主机名，test为clientid即连接MQTT的客户端ID，一般以客户端唯一标识符表示，MemoryPersistence设置clientid的保存形式，默认为以内存保存
            client = new MqttClient(HOST, clientid, new MemoryPersistence());
            // MQTT的连接设置
            options = new MqttConnectOptions();
            //设置mqtt版本信息
            if("3.1.1".equals(this.version)){
                options.setMqttVersion(MqttConnectOptions.MQTT_VERSION_3_1_1);
            }else if("3.1".equals(this.version)){
                options.setMqttVersion(MqttConnectOptions.MQTT_VERSION_3_1);
            }else{
                options.setMqttVersion(MqttConnectOptions.MQTT_VERSION_DEFAULT);
            }
            log.debug("MQTT版本为===>"+options.getMqttVersion());
            //设置是否自动重连
            options.setAutomaticReconnect(automaticReconnection);
            // 设置是否清空session,这里如果设置为false表示服务器会保留客户端的连接记录，这里设置为true表示每次连接到服务器都以新的身份连接
            options.setCleanSession(cleanSession);
            log.debug("设置断开连接后是否接受消息==>"+(options.isCleanSession()?"接收":"不接收"));
            // 设置连接的用户名
            options.setUserName(userName);
            // 设置连接的密码
            options.setPassword(passWord.toCharArray());
            // 设置超时时间 单位为秒
            options.setConnectionTimeout(connectionTimeout);
            // 设置会话心跳时间 单位为秒 服务器会每隔1.5*20秒的时间向客户端发送个消息判断客户端是否在线，但这个方法并没有重连的机制
            options.setKeepAliveInterval(keepAliveInterval);
            // 设置回调
            client.setCallback(mqttCallback);
            log.debug("成功加载回调函数");
            //setWill方法，如果项目中需要知道客户端是否掉线可以调用该方法。设置最终端口的通知消息
            log.debug("正在设置断开消息。。。");
            options.setWill(this.willTopic, this.willPayload.getBytes(), 2, false);
            client.connect(options);
            log.debug("mqtt启动成功");
            log.debug("设置startTopic为空时不加载启动消息");
            //默认加载启动成功消息
            if(startTopic!=null){

                if (this.pub(this.startTopic,this.startPayload,this.startlQos)){
                    log.debug("启动消息发送成功");

                }else{
                    log.debug("启动消息发送失败");
                }
            }
        } catch (Exception e) {
            log.error("启动失败",e);
            e.printStackTrace();
            return null;
        }
        return client;
    }

    /**
     *
     * @param topic
     * @param Qos 消息质量
     * @return 订阅消息;
     */
    public boolean sub( String[] topic,int[] Qos){
        try {
            this.client.subscribe(topic, Qos);
            return true;
        } catch (Exception e) {
            log.error("消息订阅失败",e);
            e.printStackTrace();
            return false;
        }

    }

    /**
     * 推送消息
     * @param topic
     * @param message
     * @param Qos
     * @return
     */
    public boolean pub( String topic ,String  message,int Qos){
        try {
            MqttMessage mqttMessage = new MqttMessage();
            mqttMessage.setQos(Qos);
            mqttMessage.setPayload(message.getBytes());
            this.client.publish(topic,mqttMessage);
            return true;
        } catch (Exception e) {
            log.error("消息推送失败",e);
            e.printStackTrace();
            return false;
        }
    }



    public String getHOST() {
        return HOST;
    }

    public void setHOST(String HOST) {
        this.HOST = HOST;
    }

    public String getClientid() {
        return clientid;
    }

    public void setClientid(String clientid) {
        this.clientid = clientid;
    }

    public MqttClient getClient() {
        return client;
    }

    public void setClient(MqttClient client) {
        this.client = client;
    }

    public MqttConnectOptions getOptions() {
        return options;
    }

    public void setOptions(MqttConnectOptions options) {
        this.options = options;
    }

    public String getUserName() {
        return userName;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }

    public String getPassWord() {
        return passWord;
    }

    public void setPassWord(String passWord) {
        this.passWord = passWord;
    }

    public ScheduledExecutorService getScheduler() {
        return scheduler;
    }

    public void setScheduler(ScheduledExecutorService scheduler) {
        this.scheduler = scheduler;
    }

    public boolean isAutomaticReconnection() {
        return automaticReconnection;
    }

    public void setAutomaticReconnection(boolean automaticReconnection) {
        this.automaticReconnection = automaticReconnection;
    }

    public boolean isCleanSession() {
        return cleanSession;
    }

    public void setCleanSession(boolean cleanSession) {
        this.cleanSession = cleanSession;
    }

    public int getConnectionTimeout() {
        return connectionTimeout;
    }

    public void setConnectionTimeout(int connectionTimeout) {
        this.connectionTimeout = connectionTimeout;
    }

    public int getKeepAliveInterval() {
        return keepAliveInterval;
    }

    public void setKeepAliveInterval(int keepAliveInterval) {
        this.keepAliveInterval = keepAliveInterval;
    }

    public String getVersion() {
        return version;
    }

    public void setVersion(String version) {
        this.version = version;
    }

    public String getWillTopic() {
        return willTopic;
    }

    public void setWillTopic(String willTopic) {
        this.willTopic = willTopic;
    }

    public String getWillPayload() {
        return willPayload;
    }

    public void setWillPayload(String willPayload) {
        this.willPayload = willPayload;
    }

    public int getWillQos() {
        return willQos;
    }

    public void setWillQos(int willQos) {
        this.willQos = willQos;
    }

    public boolean isWillretained() {
        return willretained;
    }

    public void setWillretained(boolean willretained) {
        this.willretained = willretained;
    }

    public String getStartTopic() {
        return startTopic;
    }

    public void setStartTopic(String startTopic) {
        this.startTopic = startTopic;
    }

    public String getStartPayload() {
        return startPayload;
    }

    public void setStartPayload(String startPayload) {
        this.startPayload = startPayload;
    }

    public int getStartlQos() {
        return startlQos;
    }

    public void setStartlQos(int startlQos) {
        this.startlQos = startlQos;
    }

    public boolean isStartretained() {
        return startretained;
    }

    public void setStartretained(boolean startretained) {
        this.startretained = startretained;
    }
}
